package org.ghost.springboot.demo.component.sharding;

import org.apache.commons.lang3.StringUtils;
import org.ghost.springboot.demo.util.DateUtil;

import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.Date;

public class GhostKeyParser {
    /**
     * 1970-1-1
     */
    public static final long UNIX_BASE_DATE = LocalDateTime.of(1970, 1, 1, 0, 0, 0).atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();
    /**
     * 长整形二进制位数
     */
    public static int LONG_MAX_BIN_LEN = 64;

    private int len;
    private long epoch;

    /**
     * 构造方法
     *
     * @param len   时间位长度
     * @param epoch 基础时间毫秒数
     */
    public GhostKeyParser(int len, long epoch) {
        this.len = len;
        this.epoch = epoch;
    }

    public String getDateTime(long input) {
        String binaryString = Long.toBinaryString(input);
        int leftPadSize = LONG_MAX_BIN_LEN - binaryString.length();
        if (leftPadSize > 0) {
            //不满足64位高位补0
            binaryString = StringUtils.leftPad(binaryString, LONG_MAX_BIN_LEN, "0");
        }

        //前38位表示时间[0,42)
        long timeDiff = Long.parseLong(binaryString.substring(0, this.len + 1), 2);
        //return DateUtil.dateToStrYMD_HMS(new Date(timeDiff + this.epoch));
        //return DateUtil.dateToYMDHMS(LocalDateTime.ofInstant(Instant.ofEpochMilli(timeDiff + this.epoch), ZoneId.of("Asia/Shanghai")));
        return DateUtil.dateToStrYMD_HMS(Date.from(Instant.ofEpochMilli(timeDiff + this.epoch)));
    }

    public long getDatacenterId(long input) {
        String binaryString = Long.toBinaryString(input);
        int leftPadSize = LONG_MAX_BIN_LEN - binaryString.length();
        if (leftPadSize > 0) {
            //不满足64位高位补0
            binaryString = StringUtils.leftPad(binaryString, LONG_MAX_BIN_LEN, "0");
        }

        //前38位表示时间[0,42)
        long timeDiff = Long.parseLong(binaryString.substring(0, this.len + 1), 2);
        if (timeDiff + UNIX_BASE_DATE < this.epoch) {
            return 0L;
        }

        //5计算DatacenterId[42,47)
        //5计算WorkerId[47,52)
        //12毫秒内自增位[52,64）
        return Long.parseLong(binaryString.substring(42, 47), 2);
    }
}
